#!/bin/sh /etc/rc.common
# Copyright (C) 2020 Lienol <lawlienol@gmail.com>
# Copyright (C) 2025 WROIATE <j.wroiate@gmail.com>

USE_PROCD=1
START=99

CONFIG=socat
CONFIG_PATH=/var/etc/$CONFIG
NFT_TABLE_POST=/usr/share/nftables.d/table-post/socat.nft
NFT_CHAIN_PRE=/usr/share/nftables.d/chain-pre/input_wan/socat.nft
RULES=

remove_fw_rule() {
	echo "" >$NFT_TABLE_POST
	echo "" >$NFT_CHAIN_PRE
	fw4 reload >"/dev/null" 2>&1
	nft delete chain inet fw4 SOCAT 2>/dev/null
}

run_service() {
	config_get enable $1 enable
	[ "$enable" = "0" ] && return 0
	config_get remarks $1 remarks
	config_get protocol $1 protocol
	config_get family $1 family
	config_get proto $1 proto
	config_get listen_port $1 listen_port
	config_get reuseaddr $1 reuseaddr
	config_get dest_proto $1 dest_proto
	config_get dest_ip $1 dest_ip
	config_get dest_port $1 dest_port
	config_get proxy $1 proxy
	config_get proxy_server $1 proxy_server
	config_get proxy_port $1 proxy_port
	config_get firewall_accept $1 firewall_accept
	ln -s /usr/bin/socat ${CONFIG_PATH}/$1

	if [ "$reuseaddr" = "1" ]; then
		reuseaddr=",reuseaddr"
	else
		reuseaddr=""
	fi

	if [ "$family" = "6" ]; then
		ipv6only_params=",ipv6-v6only"
	else
		ipv6only_params=""
	fi

	# 端口转发
	if [ "$protocol" = "port_forwards" ]; then
		listen=${proto}${family}
		[ "$family" = "" ] && listen=${proto}6
		[ "$proxy" != "" ] && {
			proxy_arg=""
			[ "$proxy" = "socks4/4a" ] && {
				dest_proto="socks4a"
				proxy_arg="socksport"
			}
			[ "$proxy" = "http" ] && {
				dest_proto="proxy"
				proxy_arg="proxyport"
			}
			[ -n "$proxy_server" ] && dest_proto="${dest_proto}:${proxy_server}"
			[ -n "$proxy_port" ] && proxy_arg=",${proxy_arg}=${proxy_port}"
		}
		procd_open_instance "$remarks-$1"
		procd_set_param command ${CONFIG_PATH}/$1 ${listen}-listen:${listen_port}${ipv6only_params}${reuseaddr},fork ${dest_proto}:${dest_ip}:${dest_port}${proxy_arg}
		procd_set_param stdout 1
		procd_set_param stderr 1
		procd_close_instance
	fi

	[ "$firewall_accept" = "1" ] && append_fw_rule "$family" "$proto" "$listen_port" "$remarks"
}

append_fw_rule() {
	local family="$1"
	local proto="$2"
	local listen_port="$3"
	local remarks="$4"
	if [ -z "$family" ] || [ "$family" = "6" ]; then
		RULES="$RULES
		meta nfproto ipv6 $proto dport $listen_port counter accept comment \"$remarks\""
	fi
	if [ -z "$family" ] || [ "$family" = "4" ]; then
		RULES="$RULES
		meta nfproto ipv4 $proto dport $listen_port counter accept comment \"$remarks\""
	fi
}

set_fw_rules() {
	[ -z "$RULES" ] && return 0
	cat <<-EOF >>$NFT_TABLE_POST
		chain SOCAT {
		        $RULES
		        return
		}
	EOF
	cat <<-EOF >>$NFT_CHAIN_PRE
		jump SOCAT comment "socat rule for luci app"
	EOF
	fw4 reload >"/dev/null" 2>&1
}

stop_service() {
	remove_fw_rule
	rm -rf ${CONFIG_PATH}
}

start_service() {
	enable=$(uci -q get $CONFIG.@global[0].enable)
	if [ "$enable" = "1" ]; then
		mkdir -p $CONFIG_PATH
		config_load $CONFIG
		config_foreach run_service "config"
		set_fw_rules
	fi
}

service_triggers() {
	procd_add_reload_trigger "socat"
}

reload_service() {
	stop
	start
}
